package xyz.bali16.module.rank.service;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.gitee.starblues.annotation.Supplier;
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import xyz.bali16.application.core.utils.RedisUtil;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static xyz.bali16.application.core.utils.TimeUtil.parseStringToLocalDateTime;

/**
 * @author bali2 on 20/4/2023.
 * @version 1.0
 */
@Service
@Supplier("articleRank")
public class ArticleRankServiceImpl implements ArticleRankService {

    @Autowired
    @AutowiredType(AutowiredType.Type.MAIN_PLUGIN)
    RedisUtil redisUtil;
    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 缓存文章的基本信息
     *
     * @param expireTime
     */
    private void hashCacheArticleIdAndTitle(String articleId, String articleTitle, Integer articleCommentCount, Integer articleViews, Integer likeCount, Integer collectionCount, long expireTime) {
        // 根据文章Id获取是否有key
        String key = "rank:article:" + articleId;
        boolean hasKey = redisUtil.hasKey(key);
        // 如果不存在key就缓存下来
        if (!hasKey) {
            redisUtil.hset(key, "article:id", articleId, expireTime);
            redisUtil.hset(key, "article:title", articleTitle, expireTime);
            redisUtil.hset(key, "article:likeCount", articleCommentCount, expireTime);
            redisUtil.hset(key, "article:collectionCount", articleCommentCount, expireTime);
            redisUtil.hset(key, "article:commentCount", articleCommentCount, expireTime);
            redisUtil.hset(key, "article:views", articleViews, expireTime);
        }
    }

    /**
     * 本周合并每日评论数量操作
     */
    @Override
    @Supplier.Method("zunionAndStoreLast7DayForWeekRank")
    public void zunionAndStoreLast7DayForWeekRank(String type) {
        // 将最近7天的key的value都合成在今天里
        String currentKey = "day:rank:" + type +":"+ DateUtil.format(new Date(), DatePattern.NORM_DATE_FORMAT);

        String destKey = "week:rank:" + type;
        List<String> otherKeys = new ArrayList<>();
        for (int i = -6; i < 0; i++) {
            String temp = "day:rank:"+type+":"+
                    DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.NORM_DATE_FORMAT);
            otherKeys.add(temp);
        }

        redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);
    }

    /**
     * 评论周榜设计
     */

    /**
     * 评论数量并且合并到周排行中
     *
     * @param articleId
     * @param articleTitle
     * @param articleCommentCount
     * @param articleViews
     * @param gmtCreated
     * @param isIncr
     */
    @Supplier.Method("incrTypeCountAndUnionForWeekRank")
    public void incrTypeCountAndUnionForWeekRank(String type, String articleId, String articleTitle, Integer articleCommentCount, Integer articleViews, String gmtCreated, Integer likeCount, Integer collectionCount, boolean isIncr) {
        String currentKey = "day:rank:" + type +":"+ DateUtil.format(new Date(), DatePattern.NORM_DATE_FORMAT);
        redisUtil.zIncrementScore(currentKey, articleId, isIncr ? 1 : -1);

        LocalDateTime localDateTime = parseStringToLocalDateTime(gmtCreated.split("\\s")[0], DatePattern.NORM_DATE_FORMAT.getPattern());
        ZoneId ZONE = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(ZONE).toInstant();
        long between = DateUtil.between(new Date(), Date.from(instant), DateUnit.DAY);
        long expireTime = (7 - between) * 24 * 60 * 60; // 有效时间

        // 缓存这篇文章的基本信息
        this.hashCacheArticleIdAndTitle(articleId, articleTitle, articleCommentCount, articleViews, likeCount, collectionCount, expireTime);

        // 重新做并集
        this.zunionAndStoreLast7DayForWeekRank(type);
    }

    /**
     * 应该在Article模组初始化的时候就要调用该方法，上层方法应传入所有的articles进行initWeekRank
     */
    @Override
    @Supplier.Method("initWeekRank")
    public void initWeekRank(String type, String articleId, String articleTitle, Integer articleCommentCount, Integer articleViews, String gmtCreated, Integer likeCount, Integer collectionCount) {

        // 获取7天的发表的文章
        //List<Article> posts = this.list(new QueryWrapper<Article>()
        //        .ge("gmt_created", DateUtil.offsetDay(new Date(), -7))
        //        .select("id, title, user_id, comment_count, views, gmt_created")
        //);

        // 初始化文章的总评论量
        LocalDateTime localDateTime = parseStringToLocalDateTime(gmtCreated.split("\\s")[0], DatePattern.NORM_DATE_FORMAT.getPattern());

        String key = "day:rank:" + type +":"+localDateTime.toString().split("T")[0];
        System.out.println("测试的key" + key);
        System.out.println(articleId);
        System.out.println(articleCommentCount);

        //redisUtil.zSet(key, articleId, articleCommentCount);
        switch(type){
            case "commentCount":
                redisTemplate.opsForZSet().add(key, articleId, articleCommentCount);
                System.out.println("识别commentCount");
                break;
            case "views":
                redisTemplate.opsForZSet().add(key, articleId, articleViews);
                System.out.println("识别views");
                break;
            case "like":
                redisTemplate.opsForZSet().add(key, articleId, likeCount);
                System.out.println("识别like");
                break;
            case "collection":
                redisTemplate.opsForZSet().add(key, articleId, collectionCount);
                System.out.println("识别collection");
                break;
        }

        ZoneId ZONE = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(ZONE).toInstant();

        // 7天后自动过期(15号发表，7-（18-15）= 4)
        long between = DateUtil.between(new Date(), Date.from(instant), DateUnit.DAY);
        long expireTime = (7 - between) * 24 * 60 * 60; // 有效时间

        redisUtil.expire(key, expireTime);

        // 缓存文章的一些基本信息（id，标题，评论数量，作者）
        this.hashCacheArticleIdAndTitle(articleId, articleTitle, articleCommentCount, articleViews, likeCount, collectionCount, expireTime);
    }

    /**
     * 点击量设计
     */
    @Override
    @Supplier.Method("updateTypeCount")
    public void updateTypeCount(String type, String articleId, Integer articleValue) {
        String key = "rank:article:" + articleId;
        // 1、优先选择缓存数据
        Integer value = (Integer) redisUtil.hget(key, "article:" + type);
        // 2、如果没有，就先从实体里面获取，再加一
        if (value != null) {
            articleValue = value + 1; // 使用缓存数据+1
        } else {
            if (articleValue == 0) {
                articleValue = 1;
            } else {
                articleValue++; // 使用数据库数据+1
            }
        }
        // 3、同步到缓存里面
        redisUtil.hset(key, "article:" + type, articleValue);

    }
}


